package.cpath = "luaclib/?.so"
package.path = "lualib/?.lua;examples/client/?.lua"

local crypt = require "crypt"

if _VERSION ~= "Lua 5.3" then
	error "Use lua 5.3"
end


local randkey = {[1] = "dssferw1",[2] =  "34eghjhg",  [3] =  "34erwfgd", [4] = "2#433423",
                 [5] = "34521313",[6] =  "dfssffff",  [7] =  "erweerwe", [8] = "Fdfdfere",
                 [9] = "12342rew",[10] = "bdfdsere",  [11] = "evfgdrrt",[12] = "erwer331",
                 [13] ="223edfbf",[14] = "erwerfdf",  [15] = "45rte45$",[16] = "dfserdfe"}

local keyindex = 1

local localkey = "123"
local descmp   = "123"
local deskey   = "123"
local authed   = false
local as = 0
local total = 0
local sendlen =  256
local totalindex = 0
local start   = os.time()

local CMD = {}
local handd = false

local socket = require "clientsocket"

--local fd = assert(socket.connect("127.0.0.1", 9100))
local fd = assert(socket.connect("119.23.148.24", 9100))

local function send_package(fd, pack)
    --print("send_package 1")
	local package = string.pack(">s2", pack)
    --print("send_package 2")
	socket.send(fd, package)
end

local function unpack_package(text)
	local size = #text
	if size < 2 then
		return nil, text
	end
	local s = text:byte(1) * 256 + text:byte(2)
	if size < s+2 then
		return nil, text
	end

    --print("unpack_package: sz:"..s)
	return text:sub(3,2+s), text:sub(3+s)
end

local function recv_package(last)
	local result
	result, last = unpack_package(last)
	if result then
		return result, last
	end
	local r = socket.recv(fd)
	if not r then
		return nil, last
	end
	if r == "" then
		error "Server closed"
	end
	return unpack_package(last .. r)
end

local session = 0

local function send_w(mcmd, scmd,str)
	local data = "123"
	if str then
    	data = string.pack(">I2>I2c"..(string.len(str)),mcmd,scmd,str)
    else
    	data = string.pack(">I2>I2",mcmd,scmd)
    end
	send_package(fd, data)
	--print("send_w sz="..#data)
end

local function send_request(name, args)
	session = session + 1
	local str = request(name, args, session)
	send_package(fd, str)
	print("Request:", session)
end

local last = ""

local function print_request(name, args)
	print("REQUEST", name)
	if args then
		for k,v in pairs(args) do
			print(k,v)
		end
	end
end

local function print_response(session, args)
	print("RESPONSE", session)
	if args then
		for k,v in pairs(args) do
			print(k,v)
		end
	end
end

local function print_package(t, ...)
	if t == "REQUEST" then
		print_request(...)
	else
		assert(t == "RESPONSE")
		print_response(...)
	end
end

local function bin2hex(s)
     s=string.gsub(s,"(.)",function (x) return string.format("%02X ",string.byte(x)) end)
    return s
end

local function out(msg)
    print(bin2hex(msg))
end

local function recv_hand(msg)
	local ret, clientkey =  string.unpack(">I2c8",msg, 5)
 	
	local getrand = string.unpack(">I2", clientkey, 1)
    
    keyindex = math.fmod(getrand, 16) + 1
    local shakey = crypt.hmac_sha1(clientkey, string.pack("c8c8",clientkey,randkey[keyindex]))
    
    deskey = string.sub(shakey, 1, 8)

    local dststr = string.pack("c8c8c8c8",clientkey,clientkey,clientkey,clientkey)
    
    descmp = crypt.desencode(deskey, dststr)
    print("descmp="..#descmp)
    out(descmp)     
    as = 2
end

local function recv_auth(msg)
	print("hand auth")
	local ret =  string.unpack(">I2",msg, 5)

	if ret == 20 then
		print("auth ok")
        authed = true
        as = 4
	else 
		print("auth error")
        authed = false
	end
end

local haslog = false
local function recv_test(msg)
	--print("hand test")
	local ret =  string.unpack(">I2",msg, 5)
	local desdecodestr = crypt.desdecode(deskey,string.unpack("c"..(#msg-4), msg, 5))
    --print(".")
    --CMD.test()
    total = total + sendlen
    totalindex = totalindex + 1
    if (math.fmod((os.time() - start), 5) == 0) then
        if haslog == false then
            print("c="..(total*2)/(os.time()-start).." total = "..total.." time="..(os.time() - start).." index="..totalindex.." sendlen="..sendlen)
            haslog = true
        end
    else 
        haslog = false
    end
end

local function recv_msg(msg)
	local mcmd,scmd = string.unpack(">I2>I2", msg, 1) 
    --print("->c mcmd="..mcmd.." scmd="..scmd.." sz="..#msg)
    if mcmd == 100 then 
        if scmd == 1 then
        	if (#msg < 2 + 1 + 8) then
        		print("hand recv :error")
        		return	
        	end
        	recv_hand(msg)
        end

        if scmd == 2 then
        	if (#msg < (4 + 1)) then
        		print("hand auth :error sz"..#msg)
        		return
        	end

          	recv_auth(msg)
        end

        if scmd == 3 then
        	if (#msg < (4 + 1)) then
        		print("hand test :error sz"..#msg)
        		return
        	end
          	recv_test(msg)
        end
    end
end

local function dispatch_package()
	while true do
		local v
		v, last = recv_package(last)
		if not v then
			break
		end

		recv_msg(v)
	end
end


function CMD.fi()
    print("cmd connecth .....")
    send_w(100, 1)
    chd = true
end

function CMD.auth()
    print("cmd auth")

    send_w(100, 2, descmp)
end

function CMD.test()
    --print("cmd test")
    --local largevalue = string.rep("R", 63*1024)
    local largevalue = string.rep("R", sendlen)
    local sendstr = crypt.desencode(deskey, largevalue)
    send_w(100, 3, sendstr)
end

function CMD.quit()
    print("cmd quit")
    send_w(100, 4)
end


while true do
	dispatch_package()
    --[[
	local cmd = socket.readstdin()
	if cmd then
        local f = CMD[cmd]
        if f then
           f() 
        end
	else
        --]]
        socket.usleep(100)
        while true do
            if as == 0 then 
                CMD.fi()
                as = 1
                break 
            end
            if as == 2 then 
                CMD.auth()
                as = 3
                break 
            end
            if as == 4 then 
                for i=1,10 do
                    CMD.test()
                end
                break 
            end
            break
        end
	--end
end
